<template>
  <div class="goods-sku">
    <dl v-for="item in goods.specs" :key="item.name">
      <dt>{{ item.name }}</dt>
      <dd>
        <!--
          selected  选中状态类名
          disabled  禁用状态类名
        -->
        <template v-for="v in item.values" :key="v.name">
          <img
            v-if="v.picture"
            :src="v.picture"
            :alt="v.name"
            :title="v.name"
            :class="{ selected: v.selected,disabled:v.disabled }"
            @click="changeSpecs(item, v)"
          />
          <span
            v-else
            @click="changeSpecs(item, v)"
            :class="{ selected: v.selected,disabled:v.disabled }"
            >{{ v.name }}</span
          >
        </template>
      </dd>
    </dl>
  </div>
</template>
<script>
import powerSet from '@/vender/power-set'
// 获取可选集合

const spliter = '★'
// 根据有库存的规格，生成一个查询字典（用于后续用户实现选中）
const getPathMap = (skus) => {
  //   console.log(skus)
  const temp = [] // 测试用的数组
  const pathMap = {}
  // 获取到有库存的可选规格
  skus.forEach((item) => {
    // 如果有库存
    // console.log(item.inventory)
    if (item.inventory) {
      // 获取到有库存情况下的可选规格
      const valueNames = item.specs.map((v) => v.valueName)

      // 映射后结构：["蓝色", "中国", "10cm"]
      // console.log(valueNames)
      // 幂集算法 - 获取该集合的所有子集
      const powerSetValues = powerSet(valueNames)

      powerSetValues.forEach((dict) => {
        // console.log(dict)
        const key = dict.join(spliter)

        // console.log(key)
        if (!pathMap[key]) {
          pathMap[key] = [item.id]
        } else {
          pathMap[key].push(item.id)
        }

        // console.log(pathMap[key])
      })

      temp.push(powerSetValues) // 测试用的数组
    }
  })
  //   console.log(pathMap)
  //   console.log('测试用的数组', temp)
  return pathMap
}

// 获取用户选中的字段
const getSelectedArr = (specs) => {
  //   console.log(specs)
  const arr = []
  specs.forEach((spec, index) => {
    // console.log(spec)

    // 每个字段上都有属于自己的 selected
    const obj = spec.values.find((v) => v.selected === true)
    // console.log(obj)

    // 获取到选中字段的数组
    arr[index] = obj ? obj.name : undefined
    // arr.push(obj ? obj.name : undefined)
  })
  //   console.log(arr)
  return arr
}

// 更新规格选择按钮的禁用状态
const updateDisabledStatus = (specs, pathMap) => {
  // 遍历规格最外层
  specs.forEach((spec, index) => {
    // console.log(spec)

    // 获取到当前被用户选中的
    const selectedArr = getSelectedArr(specs)
    // 遍历每一行的具体规格对象
    spec.values.forEach(value => {
      // console.log(value)
      // 如果当前被遍历的值是被选中的话
      if (value.selected) return
      // 🔔模拟用户的下一次的选择操作
      selectedArr[index] = value.name
      // console.log(selectedArr)
      // 把模拟选中的规格去字典中查找是否存在，如果不存在，就设置为 disabled 禁用
      const key = selectedArr.filter(v => v !== undefined).join(spliter)
      // 每个规格都设置一个 disabled 表示当前规格是否可选
      value.disabled = !pathMap[key]
    })
  })
}

// 初始化默认选中规格
const initSelectedStatus = (goods, skuId) => {
//   console.log(goods, skuId)
// 根据 skuId 获取到对应规格字段
  const skuObj = goods.skus.find(item => {
    return item.id === skuId
  })
  //   console.log(skuObj)
  // 局部的规格字段 - 添加判断，如果父组件没有传递 skuId 也不会报错
  skuObj && skuObj.specs.forEach((item, index) => {
    const value = goods.specs[index].values.find(v => v.name === item.valueName)
    // 更新商品的总规格的数组 - 页面中显示用的
    // console.log(value)
    // 如果存在就添加选中状态
    if (value) value.selected = true

    // const value = goods.specs.find(v => v.name === item.name).values.find(v => v.name === item.valueName)
    // value.selected = true
  })
}

export default {
  name: 'GoodsSku',
  props: {
    goods: {
      type: Object,
      default: () => ({})
    },
    // skuId，如果父组件调用的时候传值过来，就实现默认的规格选中
    skuId: {
      type: String,
      default: ''
    }
  },
  setup (props, { emit }) {
    // skus    库存集合
    // specs   规格属性
    // 获取有库存规格的所有情况字典
    const pathMap = getPathMap(props.goods.skus)

    initSelectedStatus(props.goods, props.skuId)

    // 初始化的时候需要调用一次，默认情况下没有库存的选项就要被禁用
    updateDisabledStatus(props.goods.specs, pathMap)

    const changeSpecs = (theItem, theVal) => {
      // 设置禁用状态
      if (theVal.disabled) return
      // 每个可选的规格都有一个属于自己的 selected 状态
      if (theVal.selected) {
        theVal.selected = false
      } else {
        // 排他思想，排除所有同级，当前自己高亮
        theItem.values.forEach((item) => {
          item.selected = false
        })
        theVal.selected = true
      }
      // 获取到当前选中的规格：每个规格上有 selected 字段
      //   const arr = getSelectedArr(props.goods.specs)
      //   console.log('当前用户选中的字段为', arr)

      // 每次点击按钮的时候，还需要根据库存更新按钮的禁用状态
      updateDisabledStatus(props.goods.specs, pathMap)

      // 如果用户每个规格都有选中状态，就可以传递 skuId 给父组件了
      const selectedArr = getSelectedArr(props.goods.specs).filter(v => v !== undefined)
      // 如果是完整选择，选中的长度和规格的长度一致
      if (selectedArr.length === props.goods.specs.length) {
        // console.log(selectedArr)
        // 拼接成用于在字典中查询的 key 值
        const key = selectedArr.join(spliter)
        // console.log(key)
        // 根据 key 值在字典中查找 skuId
        const [skuId] = pathMap[key]
        // console.log(skuId)

        // 根据 skuId 获取商品的信息（价格，原价，库存数量）
        const { inventory, oldPrice, price, specs } = props.goods.skus.find(item => item.id === skuId)

        // 允许父组件通过 change 获取到选中的 skuId
        emit('change', {
          skuId: skuId,
          inventory,
          oldPrice,
          price,
          attrsText: specs.map(item => `${item.name}:${item.valueName}`).join(' ')
        })
      } else {
        // 如果没有选择完整规格，也要通知父组件(否则父组件不知道当前是否选择是完整的)
        emit('change', {})
      }
    }

    return { changeSpecs }
  }
}
</script>
<style scoped lang="less">
.sku-state-mixin () {
  border: 1px solid #e4e4e4;
  margin-right: 10px;
  cursor: pointer;
  &.selected {
    border-color: @xtxColor;
  }
  &.disabled {
    opacity: 0.6;
    border-style: dashed;
    cursor: not-allowed;
  }
}
.goods-sku {
  padding-left: 10px;
  padding-top: 20px;
  dl {
    display: flex;
    padding-bottom: 20px;
    align-items: center;
    dt {
      width: 50px;
      color: #999;
    }
    dd {
      flex: 1;
      color: #666;
      > img {
        width: 50px;
        height: 50px;
        .sku-state-mixin ();
      }
      > span {
        display: inline-block;
        height: 30px;
        line-height: 28px;
        padding: 0 20px;
        .sku-state-mixin ();
      }
    }
  }
}
</style>
